<?php

/**
 * \file
 * Classe `Member`.
 */

namespace pilar\Forms /* \cond */ ; /* \endcond */
{

/**
 * Membre abstrait de formulaire.
 *
 * \since 22/09/2008
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com>
 */
abstract class Member extends \object implements Atom {

/**
 * Status dans le formulaire.
 *
 * Les valeurs possibles sont : \c 'unknow', \c 'valid', \c 'invalid'.
 *
 * \since 09/10/2008
 */
protected $_status = 'unknow';


/**
 * Valeurs des champs dans le formulaire.
 *
 * \since 09/10/2008
 */
private $_values = array();


/**
 * Formulaire parent.
 *
 * \since 30/11/2008
 */
private $_form;


/**
 * Noms des champs du formulaire.
 *
 * \since 02/12/2008
 */
private $_fieldNames = array();


protected function loadDefaultParams() {
 parent::loadDefaultParams();

 $this->params->define(array(
  'name' => '', // Nom (joue le rôle d'identifiant dans le formulaire).
  'label' => '', // Libellé.
  'hidden' => false, // Si TRUE alors le membre sera présent dans le
                     // formulaire mais sous la forme de champs
                     // 'hidden' cachés.
  'notEmpty' => false  // Spécifie que le membre ne peut être 'vide'.
                       // La notion de vacuité étant relative à chaque
                       // type de membre, le comportement par défaut
                       // est de regarder si tous les champs
                       // du membre sont effectivement vides.
                       // Ce comportement peut être surchargé au
                       // travers de la méthode \c isEmpty .
 ));
}


public function onParentFormChanged(Form $f) {
 $this->_form = $f;
}


public function subMembers() {
 return array($this); // Un membre ne contient qu'un seul
                      // sous-membre : lui-même.
}


public function domNode($domDoc) {
 $domMember = $domDoc->createElement('member');

 $domMember->setAttribute('label', $this->get('label'));

 if($this->get('hidden')) {
  // Hidden flag :
   $domMember->setAttribute('hidden', 'hidden');
  // Hidden inputs :
   $domGui = $domDoc->createElement('gui');
   foreach($this->_fieldNames as $name) {
    $domInput = $domDoc->createElement('input');
    $domInput->setAttribute('type', 'hidden');
    $domInput->setAttribute('name', $this->globalId($name));
    $domInput->setAttribute('id', $this->globalId($name));
    $domGui->appendChild($domInput);
   }
   $domMember->appendChild($domGui);
 } else {
  $domMember->appendChild($this->guiDomNode($domDoc));
 }

 return $domMember;
}


/**
 * Inscrit un champ.
 *
 * \param $f Nom du champ à inscrire.
 *
 * \since 02/12/2008
 */
protected function joinField($f = 'value') {
 $this->_fieldNames[] = $f;
 $this->_values[$f] = '';
}


/**
 * Version DOM de l'interface graphique utilisateur.
 *
 * \param \DOMDocument parent.
 * \return DOMNode du GUI du membre.
 *
 * \since 22/09/2008
 */
abstract public function guiDomNode($domDoc);


/**
 * Affiche le code controlleur javascript de l'interface graphique
 * utilisateur sur la sortie standard si le membre n'est pas caché.
 * Dans le cas contraire c'est le code spécifique aux membres cachés
 * qui est affiché.
 *
 * \since 26/02/2009
 */
final public function outputController() {
 if ($this->get('hidden') == false) {
  $this->outputGuiController();
 } else {
  foreach ($this->_fieldNames as $fn) {
   $fv = $this->value($fn);
   if ($fv != '') { ?>
$('#<?php echo $this->globalId($fn) ?>').val('<?php
 echo str_replace("'", "\\'", $fv)
?>');
<?php }
  }
 }
}


/**
 * Affiche le code controlleur javascript de l'interface graphique
 * utilisateur sur la sortie standard.
 *
 * \since 02/12/2008
 */
protected function outputGuiController() {}


/**
 * Génère l'identifiant local au formulaire d'un élément XHTML de l'interface
 * graphique utilisateur.
 *
 * \param $n Identifiant local de l'élément.
 * \return Identifiant généré.
 *
 * \since 22/09/2008
 */
private function localId($n = '') {
 return  $this->get('name').(($n == '')?'':('_'.$n));
}


/**
 * Génère l'identifiant global d'un élément XHTML de l'interface graphique
 * utilisateur.
 *
 * \param $n Identifiant local de l'élément.
 * \return Identifiant généré.
 *
 * \since 28/10/2008
 **/
public function globalId($n = 'value') {
 return $this->_form->globalId(
         $this->localId($n)
        );
}


/**
 * Évalue les valeurs des champs à partir des entrées de formulaire.
 *
 * Cette méthode suppose par défaut que chaque champ a son équivalent
 * dans le formulaire. Au cas contraire il est nécessaire de la
 * surcharger.
 *
 * \since 22/09/2008
 */
protected function evalValues() {
 foreach($this->_fieldNames as $fn) {
  $this->_values[$fn] = $this->_form->postVarValue(
   $this->localId($fn)
  );
 }
}


/**
 * Vérifie une valeur donnée est acceptable pour un champ donné.
 *
 * \param $v Valeur à tester.
 * \param $f Nom du champ.
 * \return \c TRUE si la valeur est acceptable, \c FALSE sinon.
 *
 * \since 02/12/2008
 */
public function acceptsValue($v, $f = 'value') {
 return (!$this->get('notEmpty')
         || !$this->isEmpty());
}


/**
 * Regarde si le membre est 'vide'.
 *
 * \return \c TRUE si le membre est considéré comme 'vide', \c FALSE
           sinon.
 *
 * \since 28/02/2009
 */
public function isEmpty() {
 foreach ($this->_values as $fn => $v) {
  if (trim($v) != '') return false;
 }

 return true;
}


/**
 * Regarde si le champ est 'vide'.
 *
 * \param $name Nom du champ en question.
 * \return True si le champ est vide, False sinon.
 * \since 17/03/2009
 */
public function isFieldEmpty($name) {
 if (trim($this->_values[$name]) != '') {
  return false;
 }

 return true;
}


/**
 * Charge les valeurs des champs à partir du formulaire et détecte
 * d'éventuelles erreurs dans les entrées formulaires.
 *
 * \return Status.
 *
 * \see _status
 *
 * \since 09/10/2008
 */
public function loadFromGui() {
 // Evaluation des valeurs des champs depuis les entrées formulaire :
  $this->evalValues();
  
 // On regarde si pour chaque champ sa valeur est acceptée et on met à jour
 // le status en fonction du résultat des tests.
  $this->_status = 'valid';
  foreach($this->_fieldNames as $fn) {
   if(!$this->acceptsValue($this->value($fn), $fn)) {
    $this->_status = 'invalid';
   }
  }

 return $this->_status;
}


/**
 * Status.
 *
 * \return Status.
 * \see _status
 * \see loadFromGui
 *
 * \since 09/10/2008
 */
public function status() {
 return $this->_status;
}


/**
 * Change la valeur d'un champ.
 *
 * \todo
 * Vérifier que la valeur est acceptable ?
 *
 * \todo
 * Vérifier que le champ existe ?
 *
 * \param $v Valeur à assigner.
 * \param $f Nom du champ.
 *
 * \since 02/12/2008
 */
public function setValue($v, $f = 'value') {
 $this->_values[$f] = $v;
}


/**
 * Change la valeur d'un champ de manière implicite.
 *
 * \param $v Valeur à assigner.
 * \param $f Nom du champ.
 *
 * \see setValue
 *
 * \ since 02/12/2008
 */
public function __set($f, $v) {
 $this->setValue($v, $f);
}


/**
 * Valeur d'un champ.
 *
 * La méthode suppose que les valeurs des champs ont préalablement été
 * chargées via la méthode \a loadFromGui.
 *
 * \todo
 * Vérifier l'existence du champ ?
 *
 * \todo
 * Retourner une valeur par défaut en cas d'absence de valeur pour le
 * champ ?
 *
 * \param $f Nom du champ.
 * \return Valeur du champ \a $f.
 * \see loadFromForm
 *
 * \since 09/10/2008
 */
public function value($f = 'value') {
 return $this->_values[$f];
}


/**
 * Accède à la valeur d'un champ de manière implicite.
 *
 * \param $f Nom du champ.
 * \return Valeur du champ \a $f.
 *
 * \see value
 *
 * \since 02/12/2008
 */
public function __get($f) {
 return $this->value($f);
}


/**
 * Accède aux valeurs des champs.
 *
 * La méthode suppose que les valeurs des champs ont préalablement été
 * chargées via la méthode \a loadFromForm.
 *
 * \todo
 * S'assurer d'abord que les champs ont bien été chargés ?
 *
 * \since 09/10/2008
 * \return Tableau avec les valeurs des champs.
 * \see loadFromForm
 */
public function values() {
 return $this->_values;
}


/**
 * Change le status.
 *
 * \param $s Nouveau status.
 *
 * \since 03/12/2008
 */
public function setStatus($s) {
 $this->_status = $s;
}


/**
 * Noms des champs de formulaire.
 *
 * \return Tableau des noms.
 *
 * \since 08/12/2008
 */
public function fieldNames() {
 return $this->_fieldNames;
}


/**
 * Chemin d'accès des fichiers de dépendance.
 *
 * \return Tableau des chemins d'accès.
 *
 * \since 13/01/2009
 */
public function precedingFiles() {
 return array();
}


} // Class.

} // Namespace.

?>
